package ddbs;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Sched implements MSGCallback {
    public static final String msgType = "workload";
    private Map<Integer, LocalWork> wkmap;
    private List<Workload> wkloads;
    private static PeerMgr mgr;

    public Sched(PeerMgr mgr) {
        Sched.mgr = mgr;
        this.wkmap = new HashMap<Integer, LocalWork>();
        this.wkloads = new ArrayList<Workload>();
        PeerMgr.registerCallback(msgType, this);
    }

    public void addWork(LocalWork w) {
        wkmap.put(w.getId(), w);
    }

    public void rmWork(LocalWork w) {
        wkmap.remove(w);
    }
    private static void assiginSimpleWork(Work w) {
        if (w.assignto == null)
            w.assignTo(w.getDataSet().peer);
    }
    private static void assiginBinWork(BinWork w) {
        int peers[] = new int[4];
        if (w.assignto == null) {
            if (w.getW1().getStatus() == Work.STATUS && w.getW2().getStatus() == Work.STATUS) {
                w.assignTo(w.getW1().getDataSet().peer);
                //System.out.println("Sched 2 Work "+w.id);
            } else {
                for (int i = 0; i<4;++i)
                    peers[i] = 0;
                if (w.getW1().getStatus() == BinWork.STATUS) {
                    BinWork tmp = (BinWork) w.getW1();
                    peers[tmp.getW1().getDataSet().peer.getId()]++;
                    peers[tmp.getW2().getDataSet().peer.getId()]++;
                } else {
                    peers[w.getW1().getDataSet().peer.getId()]++;
                }
                if (w.getW2().getStatus() == BinWork.STATUS) {
                    BinWork tmp = (BinWork) w.getW1();
                    peers[tmp.getW1().getDataSet().peer.getId()]++;
                    peers[tmp.getW2().getDataSet().peer.getId()]++;
                } else {
                    peers[w.getW2().getDataSet().peer.getId()]++;
                }
                int max = 0, maxid = 0;
                for (int i = 0; i<4;++i) {
                    if (peers[i] > max) {
                        max = peers[1];
                        maxid = i;
                    }
                }
                w.assignTo(mgr.getPeer(maxid));
                //System.out.println("Sched 3Work #"+w.id);
            }
        }
    }

    public static void assiginWork(LocalWork w) {
        if (w.getStatus() == Work.STATUS)
            assiginSimpleWork((Work) w);
        else
            assiginBinWork((BinWork) w);

    }
    public void schedWorks(Workload wkload) {
        if (wkload.wks ==null || wkload.wks.size() <= 0)
            return;
        Iterator<LocalWork> it = wkload.wks.iterator();
        while (it.hasNext()) {
            LocalWork w = it.next();
            assiginWork(w);
            System.out.println("Sched Work #"+w.id+" to "+w.assignto.getId()+":"+w.toString());
        }
    }

    void dealwithWorkload(Workload wkload) {
        wkloads.add(wkload);
        schedWorks(wkload);
        if (wkload.wks != null) {
            Iterator<LocalWork> it = wkload.wks.iterator();
            while (it.hasNext()) {
                LocalWork w = it.next();
                // w.show(mgr);
                addWork(w);
            }
        }
        wkload.dealWith();
    }

    void finishWorkload(Workload wkload) {
        wkloads.remove(wkload);
        Iterator<LocalWork> it = wkload.wks.iterator();
        while (it.hasNext()) {
            LocalWork w = it.next();
            rmWork(w);
        }
    }

    @Override
    public void handleMsg(Peer from, MSG msg) {
        if (msg.id < 0) {
            LocalWork w = wkmap.get(new Integer(-msg.id));
            if (w == null) {
                System.out.println("found no local work ");
                msg.show();
                return;
            }
            w.handleResponse(msg);
        } else {
            ProxyWork pw = new ProxyWork(this, from, msg);
            pw.dealWith();
        }
    }

    public PeerMgr getMgr() {
        return mgr;
    }
}
